#ifndef __UDP_SERVICE_HPP__
#define __UDP_SERVICE_HPP__

#include <iostream>
#include <string>
#include <memory>
#include <unordered_map>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "Log.hpp"

#define SIZE 1024

class UDPService
{
public:
    UDPService(uint16_t port)
        :_port(port)
        ,_sock(-1)
    {}

    bool initService()
    {
        //1.创建套接字
        _sock=socket(AF_INET,SOCK_DGRAM,0);
        if(_sock<0)
        {
            logMessage(FATAL,"%d:%s\n",errno,strerror(errno));
            exit(1);
        }

        //2.bind
        struct sockaddr_in local;
        memset(&local,0,sizeof(local));
        local.sin_family=AF_INET;
        local.sin_port=htons(_port);
        local.sin_addr.s_addr=INADDR_ANY;

        if(bind(_sock,(struct sockaddr*)&local,sizeof(local))<0)
        {
            logMessage(FATAL,"%d:%s\n",errno,strerror(errno));
            exit(2);
        }

        logMessage(NORMAL,"%s->%d:%s\n","initServer success",errno,strerror(errno));
        return true;
    }

    void start()
    {

        //第一步：初步验证了服务器的收发逻辑
        // char buff[SIZE];
        // while(true)
        // {
        //     memset(buff,0,sizeof(buff));
        //     struct sockaddr_in peer;
        //     memset(&peer,0,sizeof(peer));
        //     socklen_t len=sizeof(peer);
        //     ssize_t s=recvfrom(_sock,buff,sizeof(buff)-1,0,(struct sockaddr*)&peer,&len);
        //     if(s>0)
        //     {
        //         buff[s]='\0';
        //         std::string cliIp=inet_ntoa(peer.sin_addr);
        //         uint16_t cliPort=ntohs(peer.sin_port);
        //         printf("[%s][%d]# %s\n",cliIp.c_str(),cliPort,buff);
        //         sendto(_sock,buff,s,0,(struct sockaddr*)&peer,len);
        //     }
        // }

        //第二步，进阶到群发功能，服务器
        char buff[SIZE];
        while(true)
        {
            struct sockaddr_in peer;
            memset(&peer,0,sizeof(peer));
            socklen_t len=sizeof(peer);
            ssize_t s=recvfrom(_sock,buff,SIZE-1,0,(struct sockaddr*)&peer,&len);
            std::string key;
            if(s>0)
            {
                buff[s]='\0';
                std::string cliIp=inet_ntoa(peer.sin_addr);
                std::string cliPort=std::to_string(ntohs(peer.sin_port));
                key=cliIp;
                key+="-";
                key+=cliPort;
                if(_users.find(key)==_users.end())
                {
                    _users.insert({key,peer});
                }
            }

            for(auto& iter:_users)
            {
                std::string sendMessage=key;
                sendMessage+="# ";
                sendMessage+=buff;
                sendto(_sock,sendMessage.c_str(),sendMessage.size(),0,(struct sockaddr*)&iter.second,sizeof(iter.second));
            }
        }
    }

    ~UDPService()
    {
        if(_sock>=0)
        {
            close(_sock);
        }
    }

private:
    uint16_t _port;//端口
    int _sock;//套接字

    std::unordered_map<std::string,struct sockaddr_in> _users;//用来查找不同的链接，通过拼接ip-port形成新的字符串为key值
};

#endif